From a96f66af6df4e266311f6895353ada79794cf1e3 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 14 Apr 2010 13:35:05 +0100 Subject: [PATCH] Improvements and bug fixes to continue_hypercall_on_cpu(). Signed-off-by: Keir Fraser --- xen/common/domain.c | 34 ++++++++++++++++++++++++++++++---- xen/include/xen/sched.h | 8 -------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/xen/common/domain.c b/xen/common/domain.c index 93f1789b90..6688b158d9 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -147,6 +147,8 @@ struct vcpu *alloc_vcpu( spin_lock_init(&v->virq_lock); + tasklet_init(&v->continue_hypercall_tasklet, NULL, 0); + if ( is_idle_domain(d) ) { v->runstate.state = RUNSTATE_running; @@ -587,6 +589,7 @@ static void complete_domain_destroy(struct rcu_head *head) { if ( (v = d->vcpu[i]) == NULL ) continue; + tasklet_kill(&v->continue_hypercall_tasklet); vcpu_destroy(v); sched_destroy_vcpu(v); } @@ -902,6 +905,7 @@ struct migrate_info { long (*func)(void *data); void *data; struct vcpu *vcpu; + unsigned int cpu; unsigned int nest; }; @@ -912,30 +916,48 @@ static void continue_hypercall_tasklet_handler(unsigned long _info) struct migrate_info *info = (struct migrate_info *)_info; struct vcpu *v = info->vcpu; - vcpu_sleep_sync(v); + /* + * Wait for vcpu to be entirely descheduled. We re-schedule ourselves + * meanwhile to allow other work to be done (e.g., descheduling the vcpu!). + */ + BUG_ON(vcpu_runnable(v)); + if ( v->is_running ) + { + tasklet_schedule(&v->continue_hypercall_tasklet); + return; + } + + /* Once descheduled, we need to gain access to its register state. */ + sync_vcpu_execstate(v); this_cpu(continue_info) = info; - return_reg(v) = info->func(info->data); + return_reg(v) = (info->cpu == smp_processor_id()) + ? info->func(info->data) : -EINVAL; this_cpu(continue_info) = NULL; if ( info->nest-- == 0 ) { xfree(info); vcpu_unpause(v); + put_domain(v->domain); } } int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) { - struct vcpu *curr = current; struct migrate_info *info; + if ( (cpu >= NR_CPUS) || !cpu_online(cpu) ) + return -EINVAL; + if ( cpu == smp_processor_id() ) return func(data); info = this_cpu(continue_info); if ( info == NULL ) { + struct vcpu *curr = current; + info = xmalloc(struct migrate_info); if ( info == NULL ) return -ENOMEM; @@ -943,11 +965,14 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) info->vcpu = curr; info->nest = 0; + tasklet_kill( + &curr->continue_hypercall_tasklet); tasklet_init( &curr->continue_hypercall_tasklet, continue_hypercall_tasklet_handler, (unsigned long)info); + get_knownalive_domain(curr->domain); vcpu_pause_nosync(curr); } else @@ -958,8 +983,9 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) info->func = func; info->data = data; + info->cpu = cpu; - tasklet_schedule_on_cpu(&curr->continue_hypercall_tasklet, cpu); + tasklet_schedule_on_cpu(&info->vcpu->continue_hypercall_tasklet, cpu); /* Dummy return value will be overwritten by tasklet. */ return 0; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index a22b8592ce..a1baa78e69 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -375,14 +375,6 @@ static inline void get_knownalive_domain(struct domain *d) ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTROYED)); } -/* Obtain a reference to the currently-running domain. */ -static inline struct domain *get_current_domain(void) -{ - struct domain *d = current->domain; - get_knownalive_domain(d); - return d; -} - struct domain *domain_create( domid_t domid, unsigned int domcr_flags, ssidref_t ssidref); /* DOMCRF_hvm: Create an HVM domain, as opposed to a PV domain. */ -- 2.30.2